home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 October / CHIP Turkiye Ekim 2000.iso / prog / naps / 04 / setup.exe / Gnucleus / HeaderCtrlEx.cpp < prev    next >
C/C++ Source or Header  |  2000-07-06  |  10KB  |  371 lines

  1. /********************************************************************************
  2.  
  3.     Gnucleus - A node application for the Gnutella network
  4.     Copyright (C) 2000 John Marshall
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     For support, questions, comments, etc...
  20.     E-Mail: 
  21.         swabby@c0re.net
  22.     
  23.     Address:
  24.         21 Cadogan Way
  25.         Nashua, NH, USA 03062
  26.  
  27. ********************************************************************************/
  28.  
  29. #include "stdafx.h"
  30. #include "HeaderCtrlEx.h"
  31.  
  32.  
  33. #ifdef _DEBUG
  34. #define new DEBUG_NEW
  35. #undef THIS_FILE
  36. static char THIS_FILE[] = __FILE__;
  37. #endif
  38.  
  39. #include "Resource.h"
  40.  
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CMyHeaderCtrl
  43.  
  44. CMyHeaderCtrl::CMyHeaderCtrl() : marker_rect(0,0,0,0)
  45. {
  46.     m_pWidth = NULL;
  47.     m_bDragging = FALSE;
  48.     m_bCheckForDrag = FALSE;
  49.     m_fpDragCol = NULL;
  50.     m_pOwnerWnd = NULL;
  51.  
  52.     // Default to being unsorted.
  53.     m_bSortAsc = FALSE;
  54.     m_nSortCol = -1;
  55. }
  56.  
  57. CMyHeaderCtrl::CMyHeaderCtrl(CWnd *pWnd, void (CWnd::*fpDragCol)(int, int))
  58.     : marker_rect(0,0,0,0)
  59. {
  60.     m_pWidth = NULL;
  61.     m_bDragging = FALSE;
  62.     m_bCheckForDrag = FALSE;
  63.     m_fpDragCol = fpDragCol;
  64.     m_pOwnerWnd = pWnd;
  65. }
  66.  
  67. CMyHeaderCtrl::~CMyHeaderCtrl()
  68. {
  69. }
  70.  
  71.  
  72. BEGIN_MESSAGE_MAP(CMyHeaderCtrl, CHeaderCtrl)
  73.     //{{AFX_MSG_MAP(CMyHeaderCtrl)
  74.     ON_WM_MOUSEMOVE()
  75.     ON_WM_LBUTTONUP()
  76.     ON_WM_LBUTTONDOWN()
  77.     //}}AFX_MSG_MAP
  78. END_MESSAGE_MAP()
  79.  
  80. /////////////////////////////////////////////////////////////////////////////
  81. // CMyHeaderCtrl message handlers
  82.  
  83. void CMyHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point)
  84. {
  85.     if( (MK_LBUTTON & nFlags) == 0)
  86.     {
  87.         // The left mouse button is not pressed - so reset flags
  88.         m_bCheckForDrag = FALSE;
  89.         m_bDragging = FALSE;
  90.     }
  91.     else if( m_bDragging )
  92.     {
  93.         // Get column number that falls under the mouse
  94.         int i=0, cx = 0;
  95.         if( point.x > 0 )
  96.             for( i = 0; i < GetItemCount(); i++ )
  97.             {
  98.                 if( point.x >= cx && point.x < cx + m_pWidth[i] )
  99.                     break;
  100.                 cx += m_pWidth[i];
  101.             }
  102.  
  103.         if( i != m_nDropPos )
  104.         {
  105.             m_nDropPos = i;
  106.  
  107.             CRect rect;
  108.             GetWindowRect( &rect );
  109.  
  110.             // Invalidate area occupied by previous marker
  111.             InvalidateRect( &marker_rect );
  112.  
  113.             // Draw a new marker
  114.             CClientDC dc(this);
  115.             POINT pts[3];
  116.             pts[0].x = cx; pts[1].x = cx -3; pts[2].x = cx +3;
  117.             pts[0].y = rect.Height(); pts[1].y = pts[2].y = rect.Height() -7;
  118.             dc.Polygon( pts, 3 );
  119.  
  120.             // save marker information
  121.             marker_rect.left = cx - 4;
  122.             marker_rect.top = rect.Height() -8;
  123.             marker_rect.right = cx + 4;
  124.             marker_rect.bottom = rect.Height();
  125.         }
  126.         return;
  127.     }
  128.     else if( m_bCheckForDrag )
  129.     {
  130.         // The mouse button was pressed over a column header
  131.         // and now the mouse has moved - so start drag
  132.         m_bCheckForDrag = FALSE;
  133.  
  134.         m_bDragging = TRUE;
  135.         m_nDropPos = m_nDragCol;
  136.  
  137.         SetCapture();
  138.  
  139.         // Store information for later use
  140.         int iCount = GetItemCount();
  141.         HD_ITEM hd_item;
  142.         m_pWidth = new int[iCount];
  143.         for( int i = 0; i < iCount; i++ )
  144.         {
  145.             hd_item.mask = HDI_WIDTH;
  146.             GetItem( i, &hd_item );
  147.             m_pWidth[i] = hd_item.cxy;
  148.  
  149.         }
  150.         return;
  151.     }
  152.     
  153.     CHeaderCtrl::OnMouseMove(nFlags, point);
  154. }
  155.  
  156. /**
  157.   * Finish a column drag if one was started.
  158.   */
  159. void CMyHeaderCtrl::OnLButtonUp(UINT nFlags, CPoint point)
  160. {
  161.     ASSERT( m_pOwnerWnd != NULL && m_fpDragCol != NULL );
  162.  
  163.     if( m_bDragging )
  164.     {
  165.         m_bDragging = FALSE;
  166.         delete[] m_pWidth;
  167.         ReleaseCapture();
  168.         Invalidate();
  169.  
  170.         // Call the callback function.
  171.         if( m_nDragCol != m_nDropPos && m_nDragCol != m_nDropPos -1 )
  172.         {
  173.             (m_pOwnerWnd->*m_fpDragCol)( m_nDragCol, m_nDropPos );
  174.             
  175.             // If the currently sorted column is the one being dragged
  176.             // Mark it as being sorted in its dropped position
  177.             if ( m_nSortCol == m_nDragCol )
  178.                 SetSortImage( m_nDropPos, m_bSortAsc ); 
  179.         }
  180.     }
  181.     CHeaderCtrl::OnLButtonUp(nFlags, point);
  182. }
  183.  
  184.  
  185. /**
  186.   *  Setup a callback for the dragging of a column
  187.   *
  188. */
  189. void CMyHeaderCtrl::SetCallback( CWnd* pWnd, void (CWnd::*fpDragCol)(int, int) )
  190. {
  191.     m_fpDragCol = fpDragCol;
  192.     m_pOwnerWnd = pWnd;
  193. }
  194.  
  195. /**
  196.   * See if a drag is starting over one of the columns.
  197.  */
  198. void CMyHeaderCtrl::OnLButtonDown(UINT nFlags, CPoint point)
  199. {
  200.     // Determine if mouse was pressed over a column header
  201.     HD_HITTESTINFO hd_hittestinfo;
  202.     hd_hittestinfo.pt = point;
  203.     SendMessage(HDM_HITTEST, 0, (LPARAM)(&hd_hittestinfo));
  204.     if( hd_hittestinfo.flags == HHT_ONHEADER )
  205.     {
  206.         m_nDragCol = hd_hittestinfo.iItem;
  207.         m_bCheckForDrag = TRUE;
  208.     }
  209.     
  210.     CHeaderCtrl::OnLButtonDown(nFlags, point);
  211. }
  212.  
  213. /**
  214.   * Set the type of image to display in this column.
  215.   * (Either ascending, or descending)
  216.   */
  217. int CMyHeaderCtrl::SetSortImage( int nCol, BOOL bAsc )
  218. {
  219.         m_nSortCol = nCol;
  220.         m_bSortAsc = bAsc;
  221.  
  222.         // Change the item to ownder drawn
  223.         HD_ITEM hditem;
  224.  
  225.         hditem.mask = HDI_FORMAT;
  226.         GetItem( nCol, &hditem );
  227.         hditem.fmt |= HDF_OWNERDRAW;
  228.         SetItem( nCol, &hditem );
  229.  
  230.         // Invalidate header control so that it gets redrawn
  231.         Invalidate();
  232.  
  233.         return 1;
  234. }
  235.  
  236.  
  237. void CMyHeaderCtrl::RemoveSortImage( int iItem )
  238. {
  239.     if( iItem != -1 )
  240.     {
  241.         HD_ITEM hditem;    
  242.         hditem.mask = HDI_FORMAT;
  243.         GetItem( iItem, &hditem );
  244.         hditem.mask = HDI_FORMAT;    
  245.         hditem.fmt &= ~HDF_BITMAP;
  246.         SetItem( iItem, &hditem );
  247.     }
  248. }
  249.  
  250. void CMyHeaderCtrl::RemoveAllSortImages()
  251. {
  252.     int iCount = GetItemCount();
  253.     for( int i = 0; i < iCount; i++ )
  254.         RemoveSortImage( i );
  255. }
  256.  
  257.  
  258.  
  259. void CMyHeaderCtrl::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
  260. {
  261.         CDC dc;
  262.  
  263.         dc.Attach( lpDrawItemStruct->hDC );
  264.  
  265.         // Get the column rect
  266.         CRect rcLabel( lpDrawItemStruct->rcItem );
  267.  
  268.         // Save DC
  269.         int nSavedDC = dc.SaveDC();
  270.  
  271.         // Set clipping region to limit drawing within column
  272.         CRgn rgn;
  273.         rgn.CreateRectRgnIndirect( &rcLabel );
  274.         dc.SelectObject( &rgn );
  275.         rgn.DeleteObject();
  276.  
  277. #pragma warning( push , 3)
  278.         // Draw the background
  279.         dc.FillRect(rcLabel, &CBrush(::GetSysColor(COLOR_3DFACE)));
  280. #pragma warning( pop )
  281.  
  282.         // Labels are offset by a certain amount  
  283.         // This offset is related to the width of a space character
  284.         int offset = dc.GetTextExtent(_T(" "), 1 ).cx*2;
  285.  
  286.  
  287.         // Get the column text and format
  288.         TCHAR buf[256];
  289.         HD_ITEM hditem;
  290.         
  291.         hditem.mask = HDI_TEXT | HDI_FORMAT;
  292.         hditem.pszText = buf;
  293.         hditem.cchTextMax = 255;
  294.  
  295.         GetItem( lpDrawItemStruct->itemID, &hditem );
  296.  
  297.         // Determine format for drawing column label
  298.         UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP 
  299.                                                 | DT_VCENTER | DT_END_ELLIPSIS ;
  300.  
  301.         if( hditem.fmt & HDF_CENTER)
  302.                 uFormat |= DT_CENTER;
  303.         else if( hditem.fmt & HDF_RIGHT)
  304.                 uFormat |= DT_RIGHT;
  305.         else
  306.                 uFormat |= DT_LEFT;
  307.  
  308.         // Adjust the rect if the mouse button is pressed on it
  309.         if( lpDrawItemStruct->itemState == ODS_SELECTED )
  310.         {
  311.                 rcLabel.left++;
  312.                 rcLabel.top += 2;
  313.                 rcLabel.right++;
  314.         }
  315.  
  316.         // Adjust the rect further if Sort arrow is to be displayed
  317.         if( lpDrawItemStruct->itemID == (UINT)m_nSortCol )
  318.         {
  319.                 rcLabel.right -= 3 * offset;
  320.         }
  321.  
  322.         rcLabel.left += offset;
  323.         rcLabel.right -= offset;
  324.  
  325.         // Draw column label
  326.         if( rcLabel.left < rcLabel.right )
  327.                 dc.DrawText(buf,-1,rcLabel, uFormat);
  328.  
  329.         // Draw the Sort arrow
  330.         if( lpDrawItemStruct->itemID == (UINT)m_nSortCol )
  331.         {
  332.                 CRect rcIcon( lpDrawItemStruct->rcItem );
  333.  
  334.                 // Set up pens to use for drawing the triangle
  335.                 CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
  336.                 CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
  337.                 CPen *pOldPen = dc.SelectObject( &penLight );
  338.  
  339.                 if( m_bSortAsc )
  340.                 {
  341.                         // Draw triangle pointing upwards
  342.                         dc.MoveTo( rcIcon.right - 2*offset, offset-1);
  343.                         dc.LineTo( rcIcon.right - 3*offset/2, rcIcon.bottom - offset );
  344.                         dc.LineTo( rcIcon.right - 5*offset/2-2, rcIcon.bottom - offset );
  345.                         dc.MoveTo( rcIcon.right - 5*offset/2-1, rcIcon.bottom - offset-1 );
  346.  
  347.                         dc.SelectObject( &penShadow );
  348.                         dc.LineTo( rcIcon.right - 2*offset, offset-2);
  349.                 }
  350.                 else
  351.                 {
  352.                         // Draw triangle pointing downwords
  353.                         dc.MoveTo( rcIcon.right - 3*offset/2, offset-1);
  354.                         dc.LineTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset + 1 );
  355.                         dc.MoveTo( rcIcon.right - 2*offset-1, rcIcon.bottom - offset );
  356.  
  357.                         dc.SelectObject( &penShadow );
  358.                         dc.LineTo( rcIcon.right - 5*offset/2-1, offset -1 );
  359.                         dc.LineTo( rcIcon.right - 3*offset/2, offset -1);
  360.                 }
  361.  
  362.                 // Restore the pen
  363.                 dc.SelectObject( pOldPen );
  364.         }
  365.  
  366.         // Restore dc
  367.         dc.RestoreDC( nSavedDC );
  368.  
  369.         // Detach the dc before returning
  370.         dc.Detach();
  371. }